/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.structure.resource.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.listener.CommonDataChangeEventCenter;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.core.enums.BizDataTypeEnum;
import vip.xiaonuo.biz.modular.structure.relation.entity.BizRelation;
import vip.xiaonuo.biz.modular.structure.relation.enums.BizRelationCategoryEnum;
import vip.xiaonuo.biz.modular.structure.relation.service.BizRelationService;
import vip.xiaonuo.biz.modular.structure.resource.entity.BizButton;
import vip.xiaonuo.biz.modular.structure.resource.entity.BizMenu;
import vip.xiaonuo.biz.modular.structure.resource.enums.BizResourceCategoryEnum;
import vip.xiaonuo.biz.modular.structure.resource.mapper.BizButtonMapper;
import vip.xiaonuo.biz.modular.structure.resource.param.button.BizButtonAddParam;
import vip.xiaonuo.biz.modular.structure.resource.param.button.BizButtonEditParam;
import vip.xiaonuo.biz.modular.structure.resource.param.button.BizButtonIdParam;
import vip.xiaonuo.biz.modular.structure.resource.param.button.BizButtonPageParam;
import vip.xiaonuo.biz.modular.structure.resource.service.BizButtonService;
import vip.xiaonuo.biz.modular.structure.resource.service.BizMenuService;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 按钮Service接口实现类
 *
 * @author xuyuxiang
 * @date 2022/6/27 14:25
 **/
@Service
public class BizButtonServiceImpl extends ServiceImpl<BizButtonMapper, BizButton> implements BizButtonService {

    @Resource
    private BizRelationService bizRelationService;

    @Resource
    private BizMenuService bizMenuService;

    @Override
    public Page<BizButton> page(BizButtonPageParam bizButtonPageParam) {
        QueryWrapper<BizButton> queryWrapper = new QueryWrapper<BizButton>().checkSqlInjection();
        queryWrapper.lambda().eq(BizButton::getCategory, BizResourceCategoryEnum.BUTTON.getValue());
        if(ObjectUtil.isNotEmpty(bizButtonPageParam.getParentId())) {
            queryWrapper.lambda().eq(BizButton::getParentId, bizButtonPageParam.getParentId());
        }
        if(ObjectUtil.isNotEmpty(bizButtonPageParam.getSearchKey())) {
            queryWrapper.lambda().like(BizButton::getTitle, bizButtonPageParam.getSearchKey());
        }
        if(ObjectUtil.isAllNotEmpty(bizButtonPageParam.getSortField(), bizButtonPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(bizButtonPageParam.getSortOrder());
            queryWrapper.orderBy(true, bizButtonPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(bizButtonPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(BizButton::getSortCode);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(BizButtonAddParam bizButtonAddParam) {
        BizButton bizButton = BeanUtil.toBean(bizButtonAddParam, BizButton.class);
        boolean repeatCode = this.count(new LambdaQueryWrapper<BizButton>()
                .eq(BizButton::getCategory, BizResourceCategoryEnum.BUTTON.getValue())
                .eq(BizButton::getCode, bizButton.getCode())) > 0;
        if(repeatCode) {
            throw new CommonException("存在重复的按钮，编码为：{}", bizButton.getCode());
        }
        bizButton.setCategory(BizResourceCategoryEnum.BUTTON.getValue());
        this.save(bizButton);

        // 发布增加事件
        CommonDataChangeEventCenter.doAddWithData(BizDataTypeEnum.RESOURCE.getValue(), JSONUtil.createArray().put(bizButton));
    }

    @Override
    public void addForGenButton(String menuId, String className, String functionName,String path) {
        BizMenu bizMenu = bizMenuService.queryEntity(menuId);
        String classNameFirstLower = StrUtil.lowerFirst(className);//以下修改添加按钮时，同时添加component，并作为后端权限标识  by Mr.wu 2024-03-24
        CollectionUtil.newArrayList(JSONUtil.createObj().set("title", "新增" + functionName).set("code", classNameFirstLower + "Add").set("sortCode", 1).set("component",StrUtil.removePrefix(path, StrUtil.SLASH) + StrUtil.SLASH + "add"),
                JSONUtil.createObj().set("title", "编辑" + functionName).set("code", classNameFirstLower + "Edit").set("sortCode", 2).set("component",StrUtil.removePrefix(path, StrUtil.SLASH) + StrUtil.SLASH + "edit"),
                JSONUtil.createObj().set("title", "删除" + functionName).set("code", classNameFirstLower + "Delete").set("sortCode", 3).set("component",StrUtil.removePrefix(path, StrUtil.SLASH) + StrUtil.SLASH + "delete"),
                JSONUtil.createObj().set("title", "批量删除").set("code", classNameFirstLower + "BatchDelete").set("sortCode", 4).set("component",StrUtil.removePrefix(path, StrUtil.SLASH) + StrUtil.SLASH + "delete")).forEach(jsonObject -> {
            BizButtonAddParam bizButtonAddParam = new BizButtonAddParam();
            BeanUtil.copyProperties(jsonObject, bizButtonAddParam);
            bizButtonAddParam.setParentId(bizMenu.getId());
            this.add(bizButtonAddParam);
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BizButtonEditParam bizButtonEditParam) {
        BizButton bizButton = this.queryEntity(bizButtonEditParam.getId());
        BeanUtil.copyProperties(bizButtonEditParam, bizButton);
        boolean repeatCode = this.count(new LambdaQueryWrapper<BizButton>()
                .eq(BizButton::getCategory, BizResourceCategoryEnum.BUTTON.getValue())
                .eq(BizButton::getCode, bizButton.getCode())
                .ne(BizButton::getId, bizButtonEditParam.getId())) > 0;
        if(repeatCode) {
            throw new CommonException("存在重复的按钮，编码为：{}", bizButton.getCode());
        }
        this.updateById(bizButton);

        // 发布更新事件
        CommonDataChangeEventCenter.doUpdateWithData(BizDataTypeEnum.RESOURCE.getValue(), JSONUtil.createArray().put(bizButton));
    }

    @Override
    public void delete(List<BizButtonIdParam> bizButtonIdParamList) {
        List<String> buttonIdList = CollStreamUtil.toList(bizButtonIdParamList, BizButtonIdParam::getId);
        if(ObjectUtil.isNotEmpty(buttonIdList)) {
            // 获取按钮的父菜单id集合
            List<String> parentMenuIdList = bizMenuService.list(new LambdaQueryWrapper<BizMenu>().in(BizMenu::getId, buttonIdList)
                    .eq(BizMenu::getCategory, BizResourceCategoryEnum.BUTTON.getValue())).stream().map(BizMenu::getParentId)
                    .collect(Collectors.toList());
            if(ObjectUtil.isNotEmpty(parentMenuIdList)) {
                bizRelationService.list(new LambdaQueryWrapper<BizRelation>().in(BizRelation::getTargetId, parentMenuIdList)
                        .eq(BizRelation::getCategory, BizRelationCategoryEnum.SYS_ROLE_HAS_RESOURCE.getValue())
                        .isNotNull(BizRelation::getExtJson)).forEach(bizRelation -> {
                    JSONObject extJsonObject = JSONUtil.parseObj(bizRelation.getExtJson());
                    List<String> buttonInfoList = extJsonObject.getBeanList("buttonInfo", String.class);
                    if (ObjectUtil.isNotEmpty(buttonInfoList)) {
                        Set<String> intersectionDistinct = CollectionUtil.intersectionDistinct(buttonIdList, buttonInfoList);
                        if(ObjectUtil.isNotEmpty(intersectionDistinct)) {
                            Collection<String> disjunction = CollectionUtil.disjunction(buttonInfoList, intersectionDistinct);
                            extJsonObject.set("buttonInfo", disjunction);
                        }
                    }
                    // 清除对应的角色与资源信息中的【授权的按钮信息】
                    bizRelationService.update(new LambdaUpdateWrapper<BizRelation>().eq(BizRelation::getId, bizRelation.getId())
                            .set(BizRelation::getExtJson, JSONUtil.toJsonStr(extJsonObject)));
                });
                // 执行删除
                this.removeByIds(buttonIdList);

                // 发布删除事件
                CommonDataChangeEventCenter.doDeleteWithDataId(BizDataTypeEnum.RESOURCE.getValue(), buttonIdList);
            }
        }
    }

    @Override
    public BizButton detail(BizButtonIdParam bizButtonIdParam) {
        return this.queryEntity(bizButtonIdParam.getId());
    }

    @Override
    public BizButton queryEntity(String id) {
        BizButton bizButton = this.getById(id);
        if(ObjectUtil.isEmpty(bizButton)) {
            throw new CommonException("按钮不存在，id值为：{}", id);
        }
        return bizButton;
    }
}
